#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import json
import logging

from logging.handlers import SMTPHandler, RotatingFileHandler

from werkzeug import import_string
from flask import Flask, g, session, request, flash, redirect, jsonify, url_for,\
    render_template

from flask.ext.principal import Principal, RoleNeed, UserNeed, identity_loaded
from flaskext.uploads import configure_uploads

from planet.extensions import db, mail, cache, photos

from planet import helpers
from planet.account.models import User

DEFAULT_BLUEPRINTS = [
    'planet.god:backend',
    'planet.account:frontend',
    'planet.account:backend',
    'planet.account:api',
    'planet.post:backend',
    'planet.post:frontend',
    'planet.post:api',
    'planet.media:backend',
    'planet.media:api',

]

def create_app(config=None, blueprints=None):

    if blueprints is None:
        blueprints = DEFAULT_BLUEPRINTS

    app = Flask(__name__)

    # config
    app.config.from_pyfile(config)
    
    configure_extensions(app)
    
    configure_identity(app)
    configure_logging(app)
    configure_errorhandlers(app)
    # configure_before_handlers(app)
    configure_template_filters(app)
    # configure_context_processors(app)
    configure_uploads(app, (photos,))
    
    # register module
    configure_blueprints(app, blueprints)

    return app

def configure_extensions(app):
    # configure extensions
    db.init_app(app)
    mail.init_app(app)
    cache.init_app(app)

def configure_identity(app):

    principal = Principal(app)

    @identity_loaded.connect_via(app)
    def on_identity_loaded(sender, identity):
        g.user = User.query.from_identity(identity)

def configure_template_filters(app):
    
    @app.template_filter()
    def json_loads(value):
        return json.loads(value)

    @app.template_filter()
    def xrange(value):
        return xrange(value+1)

    @app.template_filter()
    def format_datetime(time,s='full'):
        return helpers.format_datetime(time,s)

    @app.template_filter()
    def linebreaksbr(value):
        return value.replace('\r\n', '<br />')

    @app.template_filter()
    def photo(value):
        return photos.url(value)

    @app.template_filter()
    def get_photo(value):
        return photos.url('%s/%s.%s' % \
                        (value.get('image_path'), \
                        value.get('image_name'), \
                        value.get('image_extension_name')))

def configure_errorhandlers(app):
    
    @app.errorhandler(401)
    def unauthorized(error):
        if request.is_xhr:
            message = {
                'status' : 401,
                'message': 'Login required',
            }
            resp = jsonify(message)
            resp.status_code = 401
            return resp
        flash("Please login to see this page", "error")
        return redirect(url_for("account_backend.login", next=request.path))

    @app.errorhandler(402)
    def authorize_failed(error):
        message = {
            'status' : 402,
            'message': 'Authentication Failed',
        }
        resp = jsonify(message)
        resp.status_code = 401
        return resp
  
    @app.errorhandler(403)
    def forbidden(error):
        if request.is_xhr:
            message = {
                'status' : 403,
                'message': 'Sorry, page not allowed',
            }
            resp = jsonify(message)
            resp.status_code = 403
            return resp
        return render_template("errors/403.html", error=error)

    @app.errorhandler(404)
    def page_not_found(error):
        message = {
            'status' : 404,
            'message': 'Not Found: ' + request.url,
        }
        resp = jsonify(message)
        resp.status_code = 404
        return resp

    @app.errorhandler(500)
    def server_error(error):
        if request.is_xhr:
            return jsonify(error=_('Sorry, an error has occurred'))
        return render_template("errors/500.html", error=error)

def configure_blueprints(app, blueprints):
    blueprints_list = []
    packages_list = []

    for name in blueprints:
        # print name
        blueprint = import_string(name)
        blueprints_list.append(blueprint)
        # print blueprint.import_name
        package = import_string(blueprint.import_name)
        packages_list.append(package)
        # __import__('icosta.event.api')

        # for member_name in getattr(package, '__all__', []):
        #     print 'blueprint.import_name, member_name','%s.%s' % (blueprint.import_name, member_name)
        #     import_string('%s.%s' % (blueprint.import_name, member_name))

        # app.register_blueprint(blueprint)

    for package in list(set(packages_list)):
        for member_name in getattr(package, '__all__', []):
            # print '%s.%s' % (package.__name__, member_name)
            __import__('%s.%s' % (package.__name__, member_name))

    for blueprint in list(set(blueprints_list)):
        app.register_blueprint(blueprint)



def configure_logging(app):
    mail_handler = \
        SMTPHandler(app.config['MAIL_SERVER'],
                    app.config['DEFAULT_MAIL_SENDER'],
                    app.config['ADMINS'],
                    'application error',
                    (
                        app.config['MAIL_USERNAME'],
                        app.config['MAIL_PASSWORD'],
                    ))
    mail_handler.setLevel(logging.ERROR)
    app.logger.addHandler(mail_handler)

    formatter = logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s '
        '[in %(pathname)s:%(lineno)d]')

    debug_log = os.path.join(app.root_path, 
                             app.config['DEBUG_LOG'])

    debug_file_handler = \
        RotatingFileHandler(debug_log,
                            maxBytes=100000,
                            backupCount=10)

    debug_file_handler.setLevel(logging.DEBUG)
    debug_file_handler.setFormatter(formatter)
    app.logger.addHandler(debug_file_handler)

    error_log = os.path.join(app.root_path, 
                             app.config['ERROR_LOG'])

    error_file_handler = \
        RotatingFileHandler(error_log,
                            maxBytes=100000,
                            backupCount=10)

    error_file_handler.setLevel(logging.ERROR)
    error_file_handler.setFormatter(formatter)
    app.logger.addHandler(error_file_handler)

        